/**
 * @name DTrace unsafe index
 * @description DTrace registers are user-controllable, so they must not be
 *              used to index an array without a bounds check.
 * @kind path-problem
 * @problem.severity warning
 * @id apple-xnu/cpp/dtrace-unsafe-index
 */

import cpp
import semmle.code.cpp.dataflow.DataFlow
import DataFlow::PathGraph

class RegisterAccess extends ArrayExpr {
  RegisterAccess() {
    exists (LocalScopeVariable regs, Function emulate
    | regs.getName() = "regs" and
      emulate.getName() = "dtrace_dif_emulate" and
      regs.getFunction() = emulate and
      this.getArrayBase() = regs.getAnAccess())
  }
}

class PointerUse extends Expr {
  PointerUse() {
    exists (ArrayExpr ae | this = ae.getArrayOffset()) or
    exists (PointerDereferenceExpr deref | this = deref.getOperand()) or
    exists (PointerAddExpr add | this = add.getAnOperand())
  }
}

class DTraceUnsafeIndexConfig extends DataFlow::Configuration {
  DTraceUnsafeIndexConfig() {
    this = "DTraceUnsafeIndexConfig"
  }

  override predicate isSource(DataFlow::Node node) {
    node.asExpr() instanceof RegisterAccess
  }

  override predicate isSink(DataFlow::Node node) {
    node.asExpr() instanceof PointerUse
  }
}

from DTraceUnsafeIndexConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink, source, sink, "DTrace unsafe index"

/*
 * This query has 16 results. The 16th result is the vulnerability: dtrace_isa.c:817
 */
